<?php
/**
 * DolphinGTK - phpGtk framework
 *
 * Графический модуль
 *
 * @package    DolphinGTK
 * @author     Askarov Ruslan
 * @copyright  Askarov Ruslan (c) 2010.
 * @link       http://groups.google.com/group/dolphingtk
 * @license    http://www.opensource.org/licenses/gpl-license.php GPL
 * @version    0.1
 * @since      PHP v.: 5.2.1
 * @subpackage desktop
 * @category   module
 * @filesource
 */


class Apache
{
  // файл бд
  public static $db_file;
  // указатель на sqlite
  private static $sqlite;
  private static $table;


  ##############################################################################
  # Отработка событий                                                          #
  ##############################################################################


  /**
   * Метод для редактирования хоста в новом окошке
   *
   * @access public
   * @param  int $row
   * @return bool
   */
  public function prompt_win( $row = false )
  {
    if( is_numeric( $row ) ) {
      $old_value = self::$table->get_values($row, 1);
      $active   = self::$table->get_values($row, 0);
      $bottom = i18n('Change host');
      $msg = i18n('Host success changed!');
      $change = true;
    }
    else {
      $old_value = '';
      $bottom = i18n('Add host');
      $msg = i18n('Host success added!');
      $change = false;
      $active = '';
    }

    $values = Win::prompt(
      array(
        i18n('Host name') => $old_value
      ), 200, $bottom, 'new'
    );

    $new_value = trim($values[0]);

    // если небыло ничего введено, то оставляем без внимания
    if( empty($new_value) )
    {
      return false;
    }
    // если все же что-то ввели, проверим правильность введенного
    elseif( !self::is_url( $new_value ) )
    {
      Win::alert(WIN_TITLE, i18n('Invalid format Host!'),'dialog_error');
      return false;
    }

    if( !empty($new_value) && $old_value != $new_value )
    {
      if( $change === true )
      {
        self::editable( $active, $new_value, $row, $old_value );
      }
      else
      {
        self::editable( false, $new_value, $row );
      }
    }
    else {
      return false;
    }

  }




  /**
   * Метод для отлова клавиш мышки в таблице
   *
   * @access public
   * @param  int $button
   * @param  int $row
   * @return void
   */
  public function mouse_events( $button, $row )
  {
    if( $button == 3 ) {
      $menu = array(
        array( i18n('Delete'), array('Apache', 'delete', 65535, $row), false, 'delete' ),
        array( i18n('Edit'),  array('Apache', 'prompt_win', $row), false, 'edit' )
      );
      self::$table->menu($menu);
    }
  }




  /**
   * Метод для отлова клавишь клавиатуры, при работе с таблицой
   *
   * @access public
   * @param  int $key - клавиша, нажатая пользователем
   * @param  int $row - ряд, с которым работает пользователь
   * @return void
   */
  public function delete( $key = false, $row = false )
  {
    // отлавливаем клавишу Delete
    if( $key == 65535 )
    {
      // спросим пользователя желает ли он
      $conf = Win::confirm(WIN_TITLE, 'Are you sure to delete a host?');

      // и если желает
      if( $conf == true )
      {
        // подключаемся к бд
        self::$sqlite->connect();


        // получим имя хоста
        $host_name = self::$table->get_values($row, 1);
        $host_name = trim($host_name);

        self::$sqlite->delete(
          'hosts', array(
            'host' => $host_name
          )
        );

        // удаляем ряд
        self::$table->delete($row);

        // сообщение
        $msg = i18n('Host "%s" success removed!', $host_name);
        Win::alert( WIN_TITLE, $msg );
        Win::statusbar_update($msg);

        // удаляем хост
        self::delete_host($host_name);

        // подключаемся к бд
        self::$sqlite->disconnect();
      }
    }
  }




  /**
   * Метод, который отвечает за редатирование ряда
   *
   * первые 2 параметра, это значение рядов
   * 3 параметр, это редактируемы ряд
   * 4 параметр, это старое значение
   *
   * @access public
   * @param bool   $flag      - флаг
   * @param string $new_value - новое значение редактируемой ячейки
   * @param int    $row_num   - ряд в таблице, который редакируется
   * @param string $old_value - старое значение редактируемой ячейки
   * @return void or bool false
   */
  public function editable( $flag = false, $new_value, $row_num = false, $old_value = '' )
  {
    // подключаем к бд
    self::$sqlite->connect();


    // очищаем начальные+конечные пробельные символы
    $new_value = trim($new_value);
    $old_value = trim($old_value);


    // для начала проверим правильность формата хоста.
    // Если не совпал, то выведем окошко с сообщением.
    if( !self::is_url($new_value) )
    {
      Win::alert(WIN_TITLE, i18n('Format of the host is incorrect!'));

      // и вставим в ячейку старое значение
      if( $row ) self::$table->update($row_num, 1, $old_value);
      
      // и на этом закончим выполнение метода
      return false;
    }


    // проверим наличие хоста в бд
    $check = self::$sqlite->select(
        'hosts', array(
        'host' => $new_value
      )
    );

    // если у нас нет старого значения, и в бд 
    // не числиться, то это новый хост
    if( empty( $old_value ) && !$check['num'] )
    {
      self::$sqlite->insert(
        'hosts', array(
          'flag' => 1,
          'host' => $new_value
        )
      );
      //self::$table->update($row_num, 0, true);
      
      if( is_numeric($row_num) ) {
      self::$table->update($row_num, false, array(false,''));
      }
      self::$table->insert( array(true, $new_value), true );

      // создаём хост
      self::create_host($new_value);

      // сообщение
      Win::statusbar_update( i18n('Host "%s" success added ...', $new_value) );
    }
    // если оно было, то значит просто
    // нужно обновить ряд
    else
    {
      self::$sqlite->update(
        'hosts', array(
          'flag' => $flag,
          'host' => $new_value
        ), array(
          'host' => (!$check['num']) ? $old_value : $new_value
        )
      );

      self::$table->update(
        $row_num, false, array( $flag, $new_value )
      );
      
      #-------------------------------------------------------------#
      // Ловим момент с флагами для активации и деактивации хостов //
      if( $check['num'] > 0 )
      {
        if( $flag == true ) {
          self::ensite($new_value);
          self::restart();
          $msg = i18n('Host "%s" is active ...', $new_value);
        } else {
          self::dissite($new_value);
          self::restart();
          $msg = i18n('Host "%s" inactive ...', $new_value);
        }
        // сообщение в статус-бар
        Win::statusbar_update( $msg );
      }
      else
      {
        // обновляем хост
        self::update_host($old_value, $new_value);
        // сообщение
        Win::statusbar_update( i18n('Host "%s" success updated ...', $new_value) );
      }
      #-------------------------------------------------------------#
    }


    self::$sqlite->disconnect();
  }




  ##############################################################################
  # Касательно передачи в основное окно                                        #
  ##############################################################################


  /**
   * Метод, который создает таблицу, и
   * передаёт обьект, основному окну
   *
   * @access public
   * @return GtkObj
   */
  public function set()
  {
    // файл, где будет храниться БД
    $db_file      = OS::get_appdata() . 'database.sqlite';
    $check_db     = file_exists($db_file);
    self::$sqlite = new Sqlite($db_file);

    // подключаем к бд
    self::$sqlite->connect();

    // если бд небыла создана, то создадим
    if( !$check_db ) {
      self::$sqlite->query("CREATE TABLE hosts (flag INTEGER, host TEXT, id INTEGER PRIMARY KEY);");
    }

    /*
    $exists_host = array(
      'metallica.dev','rock.dev', 'spider.dev'
    );

    foreach( $exists_host as $value )
    {
      self::$sqlite->insert(
        'hosts', array(
          'flag' => '',
          'host' => $value
        )
      );
    }
   */

    self::$table = new Table;


    // создадим 50 рядов изначально
    self::$table->reserve(50);

    // обозначим тип линий
    self::$table->lines('both');

    // укажем функцию, в которую будут переданны данные,
    // после редактирования
    self::$table->editable(
      true, array('Apache', 'editable')
    );

    // и зададим поля таблицы
    self::$table->create(
      array( 'checkbox', '#' ),
      array( 'string', i18n('Local sites') )
    );

    // отлавливаем клавиши
    self::$table->on_key(
      array('Apache','delete')
    );

    // отлавливаем мышь
    self::$table->on_bottom(
      array('Apache','mouse_events')
    );

    $saved = self::$sqlite->select('hosts');

    // если есть данные, то вставляем их
    if( $saved['num'] > 0 )
    {
      if( is_array( $saved['result'] ) ):

      foreach( $saved['result'] as $row => $value )
      {
        $set[] = $value['flag'];
        $set[] = $value['host'];

        self::$table->update($row, false, $set);

        unset($set);
      }

      endif;
    }

    // отключаем от бд
    self::$sqlite->disconnect();

    // и передадим таблицу в окно
    return self::$table->get(200);
  }




  ##############################################################################
  # Все что ниже, касается уже особенности ОС Linux. Если вам этот модуль так  #
  # же интересен, и вы хотите партировать это на Win или Mac, поправьте код    #
  # под особенности вашей ОС                                                   #
  ##############################################################################


  /**
   * Метод для страта apache
   *
   * @access public
   * @return void
   */
  public function start()
  {
    if( Win::$os == 'linux' ):
    $proc = OS::exec('ps -e | grep apache2 | awk \'{print $1}\' | tail -1');

    if( is_numeric( $proc ) ) {
      Win::statusbar_update( i18n('Apache already runned!') );
    }
    else {
      OS::exec('/etc/init.d/apache2 start >& /dev/null');
      Win::statusbar_update( i18n('Apache success started ...') );
    }
    endif;
  }




  /**
   * Метод для остановки apache
   *
   * @access public
   * @return void
   */
  public function stop()
  {
    if( Win::$os == 'linux' ):
    $proc = OS::exec('ps -e | grep apache2 | awk \'{print $1}\' | tail -1');

    if( is_numeric( $proc ) ) {
      OS::exec('/etc/init.d/apache2 stop >& /dev/null');
      Win::statusbar_update( i18n('Apache success stoped ...') );
    }
    else {
      Win::statusbar_update( i18n('Apache not runned!') );
    }
    endif;
  }




  /**
   * Метод для рестарта apache
   *
   * @access public
   * @return void
   */
  public function restart()
  {
    if( Win::$os == 'linux' ):
    OS::exec('/etc/init.d/apache2 restart >& /dev/null');
    endif;
  }




  /**
   * Метод для активации хоста
   *
   * @access private
   * @param  string $host
   * @return void
   */
  private function ensite( $host )
  {
    if( Win::$os == 'linux' && self::is_url( $host ) ):
    // Деактивируем сайт
    OS::exec('a2ensite '.$host.' >& /dev/null');
    OS::exec('a2ensite '.$host.'.ssl >& /dev/null');
    OS::exec('echo "127.0.0.1 '.$host.'" >> /etc/hosts');
    OS::exec('echo "127.0.0.1 www.'.$host.'" >> /etc/hosts');
    endif;
    unset($host);
  }




  /**
   * Метод для деактивации хоста
   *
   * @access private
   * @param  string $host
   * @return void
   */
  private function dissite( $host )
  {
    if( Win::$os == 'linux' && self::is_url( $host ) ):
    // Деактивируем сайт
    OS::exec('a2dissite '.$host.' >& /dev/null');
    OS::exec('a2dissite '.$host.'.ssl >& /dev/null');
    // Удаление сайта с файла hosts
    $hosts = @file('/etc/hosts');
    // если получили содержимое файла
    if( is_array($hosts) && count($hosts) > 0 ):
    foreach( $hosts as $str ) {
      if( !strpos($str, $host) ) {
        $save[] = $str;
      }
    }
    file_put_contents('/etc/hosts', implode("", $save));
    endif;
    endif;
    // обычная зачистка
    unset(
      $host, $hosts, $save, $str
    );
  }




  /**
   * Метод для создания хоста
   *
   * @access private
   * @param  string $host
   * @return void
   */
  private function create_host( $host )
  {
    if( Win::$os == 'linux' && self::is_url( $host ) ):
    // Создание директории
    OS::exec('mkdir -p /srv/www/'.$host.'/www/');

    // Создание файла
    OS::exec('echo "Hello Word!" > /srv/www/'.$host.'/www/index.html');

    // Изменение прав
    OS::exec('chmod 0777 /srv/www/'.$host.'/www/index.html');
    OS::exec('chmod 0777 /srv/www/'.$host.'/www/');

    $host_conf = "
    NameVirtualHost *:80
    <VirtualHost *:80>
    DocumentRoot /srv/www/$host/www
    ServerName $host
    ServerAlias www.$host
    ServerAdmin webmaster@$host
    </VirtualHost>";

    $ssl_conf = "
    NameVirtualHost *:443
    <VirtualHost *:443>
    SSLEngine On
    SSLCertificateFile /etc/apache2/ssl/apache.pem
    DocumentRoot /srv/www/$host/www
    ServerName $host
    ServerAlias www.$host
    ServerAdmin webmaster@$host
    </VirtualHost>";

    $host_conf = trim($host_conf);
    $ssl_conf  = trim($ssl_conf);

    // Создание конфига
    file_put_contents('/etc/apache2/sites-available/'.$host, $host_conf);
    // Создание ssl конфига
    file_put_contents('/etc/apache2/sites-available/'.$host.'.ssl', $ssl_conf);

    // активируем сайт
    self::ensite($host);
    // перезапускаем апач
    self::restart();

    endif;
  }




  /**
   * Метод для удаления хоста
   *
   * @access private
   * @param  string $host
   * @return void
   */
  private function delete_host( $host )
  {
    if( Win::$os == 'linux' && self::is_url( $host ) ):
    
    // Удаление файла конфига
    OS::exec('rm /etc/apache2/sites-available/'.$host.' >& /dev/null');
    OS::exec('rm /etc/apache2/sites-available/'.$host.'.ssl >& /dev/null');
    // Удаление директории
    OS::exec('rm -r /srv/www/'.$host.' >& /dev/null');
    
    // сначала деактивируем сайт
    self::dissite( $host );
    // и перезапускаем апач
    self::restart();

    endif;
  }




  /**
   * Метод для обновления хоста
   *
   * @param string $old_host
   * @param string $new_host
   * @return void
   */
  private function update_host( $old_host, $new_host )
  {
    if( Win::$os == 'linux' ):

    if( self::is_url( $old_host ) && self::is_url( $new_host ) )
    {
      if( file_exists('/etc/apache2/sites-available/'.$old_host) )
      {
        // деактивируем
        self::dissite($old_host);

        OS::exec('rm /etc/apache2/sites-available/'.$old_host.' >& /dev/null');
        OS::exec('rm /etc/apache2/sites-available/'.$old_host.'.ssl >& /dev/null');
        // перемещение каталогов
        OS::exec('mv /srv/www/'.$old_host.' /srv/www/'.$new_host.' >& /dev/null');

        $host_conf = "
        NameVirtualHost *:80
        <VirtualHost *:80>
        DocumentRoot /srv/www/$new_host/www
        ServerName $new_host
        ServerAlias www.$new_host
        ServerAdmin webmaster@$new_host
        </VirtualHost>";


        $ssl_conf = "
        NameVirtualHost *:443
        <VirtualHost *:443>
        SSLEngine On
        SSLCertificateFile /etc/apache2/ssl/apache.pem
        DocumentRoot /srv/www/$new_host/www
        ServerName $new_host
        ServerAlias www.$new_host
        ServerAdmin webmaster@$new_host
        </VirtualHost>";

        $host_conf = trim($host_conf);
        $ssl_conf  = trim($ssl_conf);

        // Создание конфига
        file_put_contents('/etc/apache2/sites-available/'.$new_host, $host_conf);
        // Создание ssl конфига
        file_put_contents('/etc/apache2/sites-available/'.$new_host.'.ssl', $ssl_conf);
        
        // активируем сайт
        self::ensite($new_host);
        // перезапускаем апач
        self::restart();
      }
    }

    endif;
  }

  /**
   * Метод для проверки формата хоста
   *
   * @access private
   * @param  string $url
   * @return bool
   */
  private function is_url( $url = false )
  {
    if( $url === false ) return false;
    return (!preg_match("/^(([\w, -]+\.)(.*))$/ix", $url)) ? false : true;
  }

}
?>